/*
 * SimpleRecipesView.java
 */
package simplerecipes;

import java.awt.Desktop;
import java.awt.Point;
import java.beans.PropertyChangeEvent;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.net.URISyntaxException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.event.TableModelEvent;
import org.jdesktop.application.Action;
import org.jdesktop.application.ResourceMap;
import org.jdesktop.application.SingleFrameApplication;
import org.jdesktop.application.FrameView;
import org.jdesktop.application.TaskMonitor;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.beans.PropertyChangeListener;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.InputStreamReader;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Properties;
import javax.swing.DefaultCellEditor;
import javax.swing.DefaultComboBoxModel;
import javax.swing.Timer;
import javax.swing.Icon;
import javax.swing.JComboBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JOptionPane;
import javax.swing.JTabbedPane;
import javax.swing.event.HyperlinkEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.JTableHeader;
import javax.swing.table.TableColumn;
import javax.swing.text.DefaultStyledDocument;
import javax.swing.text.EditorKit;
import simplerecipes.model.Ingredient;
import simplerecipes.model.IngredientType;
import simplerecipes.model.MeasurementType;
import simplerecipes.model.MesuredIngredient;
import simplerecipes.model.Recipe;
import simplerecipes.model.Unit;

/**
 * The application's main frame.
 */
public class SimpleRecipesView extends FrameView implements PropertyChangeListener {

    public SimpleRecipesView(SingleFrameApplication app) {
        super(app);

        initComponents();

        // status bar initialization - message timeout, idle icon and busy animation, etc
        ResourceMap resourceMap = getResourceMap();
        int messageTimeout = resourceMap.getInteger("StatusBar.messageTimeout");
        messageTimer = new Timer(messageTimeout, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                statusMessageLabel.setText("");
            }
        });
        messageTimer.setRepeats(false);
        int busyAnimationRate = resourceMap.getInteger("StatusBar.busyAnimationRate");
        for (int i = 0; i < busyIcons.length; i++) {
            busyIcons[i] = resourceMap.getIcon("StatusBar.busyIcons[" + i + "]");
        }
        busyIconTimer = new Timer(busyAnimationRate, new ActionListener() {

            public void actionPerformed(ActionEvent e) {
                busyIconIndex = (busyIconIndex + 1) % busyIcons.length;
                statusAnimationLabel.setIcon(busyIcons[busyIconIndex]);
            }
        });
        idleIcon = resourceMap.getIcon("StatusBar.idleIcon");
        statusAnimationLabel.setIcon(idleIcon);
        progressBar.setVisible(false);

        // connecting action tasks to status bar via TaskMonitor
        TaskMonitor taskMonitor = new TaskMonitor(getApplication().getContext());
        taskMonitor.addPropertyChangeListener(new java.beans.PropertyChangeListener() {

            public void propertyChange(java.beans.PropertyChangeEvent evt) {
                String propertyName = evt.getPropertyName();
                if ("started".equals(propertyName)) {
                    if (!busyIconTimer.isRunning()) {
                        statusAnimationLabel.setIcon(busyIcons[0]);
                        busyIconIndex = 0;
                        busyIconTimer.start();
                    }
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(true);
                } else if ("done".equals(propertyName)) {
                    busyIconTimer.stop();
                    statusAnimationLabel.setIcon(idleIcon);
                    progressBar.setVisible(false);
                    progressBar.setValue(0);
                } else if ("message".equals(propertyName)) {
                    String text = (String) (evt.getNewValue());
                    statusMessageLabel.setText((text == null) ? "" : text);
                    messageTimer.restart();
                } else if ("progress".equals(propertyName)) {
                    int value = (Integer) (evt.getNewValue());
                    progressBar.setVisible(true);
                    progressBar.setIndeterminate(false);
                    progressBar.setValue(value);
                }
            }
        });
        
        simpleIngd.setEditorKit(simpleIngd.getEditorKitForContentType("text/html"));

        loadIngredients();
        loadUnits();
        recipe = new Recipe("-- Simple Recipe --");
        recipeChanged();
    }
    JComboBox ingdList;
    JComboBox ingdUnit;

    @Action
    public void showAboutBox() {
        if (aboutBox == null) {
            JFrame mainFrame = SimpleRecipesApp.getApplication().getMainFrame();
            aboutBox = new SimpleRecipesAboutBox(mainFrame);
            aboutBox.setLocationRelativeTo(mainFrame);
        }
        SimpleRecipesApp.getApplication().show(aboutBox);
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        mainPanel = new javax.swing.JPanel();
        recipeTitle = new javax.swing.JLabel();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jScrollPane3 = new javax.swing.JScrollPane();
        ingdTable = new javax.swing.JTable();
        jPanel4 = new javax.swing.JPanel();
        newIngd = new javax.swing.JButton();
        delIngd = new javax.swing.JButton();
        jPanel2 = new javax.swing.JPanel();
        jScrollPane2 = new javax.swing.JScrollPane();
        recipeText = new javax.swing.JTextPane();
        jPanel3 = new javax.swing.JPanel();
        jScrollPane4 = new javax.swing.JScrollPane();
        simpleIngd = new javax.swing.JEditorPane();
        jPanel5 = new javax.swing.JPanel();
        jLabel8 = new javax.swing.JLabel();
        jScrollPane1 = new javax.swing.JScrollPane();
        bakerNotes = new javax.swing.JTextArea();
        jPanel6 = new javax.swing.JPanel();
        jLabel5 = new javax.swing.JLabel();
        source = new javax.swing.JTextField();
        cookingTime = new javax.swing.JTextField();
        jLabel3 = new javax.swing.JLabel();
        preparationTime = new javax.swing.JTextField();
        jLabel2 = new javax.swing.JLabel();
        readyIn = new javax.swing.JTextField();
        jLabel4 = new javax.swing.JLabel();
        jPanel7 = new javax.swing.JPanel();
        jLabel10 = new javax.swing.JLabel();
        jLabel9 = new javax.swing.JLabel();
        actFlourWeight = new javax.swing.JTextField();
        jLabel11 = new javax.swing.JLabel();
        hydLevel = new javax.swing.JTextField();
        flourWeight = new javax.swing.JTextField();
        jPanel8 = new javax.swing.JPanel();
        servingWeight = new javax.swing.JTextField();
        jLabel16 = new javax.swing.JLabel();
        costPerServing = new javax.swing.JTextField();
        totalCost = new javax.swing.JTextField();
        jLabel18 = new javax.swing.JLabel();
        jLabel12 = new javax.swing.JLabel();
        jLabel13 = new javax.swing.JLabel();
        calPerSrv = new javax.swing.JTextField();
        totalCalories = new javax.swing.JTextField();
        totalWeight = new javax.swing.JTextField();
        jLabel14 = new javax.swing.JLabel();
        jPanel9 = new javax.swing.JPanel();
        jLabel7 = new javax.swing.JLabel();
        yield = new javax.swing.JTextField();
        jLabel6 = new javax.swing.JLabel();
        jLabel15 = new javax.swing.JLabel();
        servings = new javax.swing.JSpinner();
        resizeFactor = new javax.swing.JTextField();
        menuBar = new javax.swing.JMenuBar();
        javax.swing.JMenu fileMenu = new javax.swing.JMenu();
        jMenuItem2 = new javax.swing.JMenuItem();
        jOpenRec = new javax.swing.JMenuItem();
        jSaveRec = new javax.swing.JMenuItem();
        saveAs = new javax.swing.JMenuItem();
        loadIngdMenu = new javax.swing.JMenuItem();
        javax.swing.JMenuItem exitMenuItem = new javax.swing.JMenuItem();
        jMenu1 = new javax.swing.JMenu();
        jMenu2 = new javax.swing.JMenu();
        mQuantity = new javax.swing.JRadioButtonMenuItem();
        mPercentage = new javax.swing.JRadioButtonMenuItem();
        jMenu3 = new javax.swing.JMenu();
        gUnit = new javax.swing.JRadioButtonMenuItem();
        kgUnit = new javax.swing.JRadioButtonMenuItem();
        ozUnit = new javax.swing.JRadioButtonMenuItem();
        lbUnit = new javax.swing.JRadioButtonMenuItem();
        jMenuItem1 = new javax.swing.JMenuItem();
        javax.swing.JMenu helpMenu = new javax.swing.JMenu();
        javax.swing.JMenuItem aboutMenuItem = new javax.swing.JMenuItem();
        statusPanel = new javax.swing.JPanel();
        javax.swing.JSeparator statusPanelSeparator = new javax.swing.JSeparator();
        statusMessageLabel = new javax.swing.JLabel();
        statusAnimationLabel = new javax.swing.JLabel();
        progressBar = new javax.swing.JProgressBar();
        buttonGroup1 = new javax.swing.ButtonGroup();
        unitGroup = new javax.swing.ButtonGroup();

        org.jdesktop.application.ResourceMap resourceMap = org.jdesktop.application.Application.getInstance(simplerecipes.SimpleRecipesApp.class).getContext().getResourceMap(SimpleRecipesView.class);
        mainPanel.setBackground(resourceMap.getColor("mainPanel.background")); // NOI18N
        mainPanel.setName("mainPanel"); // NOI18N

        recipeTitle.setFont(resourceMap.getFont("recipeTitle.font")); // NOI18N
        recipeTitle.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        recipeTitle.setText(resourceMap.getString("recipeTitle.text")); // NOI18N
        recipeTitle.setName("recipeTitle"); // NOI18N
        recipeTitle.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                recipeTitleMouseClicked(evt);
            }
        });

        jTabbedPane1.setName("jTabbedPane1"); // NOI18N
        jTabbedPane1.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jTabbedPane1StateChanged(evt);
            }
        });
        jTabbedPane1.addFocusListener(new java.awt.event.FocusAdapter() {
            public void focusGained(java.awt.event.FocusEvent evt) {
                jTabbedPane1FocusGained(evt);
            }
        });

        jPanel1.setName("jPanel1"); // NOI18N
        jPanel1.setLayout(new java.awt.BorderLayout());

        jScrollPane3.setName("jScrollPane3"); // NOI18N

        ingdTable.setModel(new javax.swing.table.DefaultTableModel(
            new Object [][] {
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null},
                {null, null, null, null}
            },
            new String [] {
                "Title 1", "Title 2", "Title 3", "Title 4"
            }
        ));
        ingdTable.setName("ingdTable"); // NOI18N
        ingdTable.addMouseListener(new java.awt.event.MouseAdapter() {
            public void mouseClicked(java.awt.event.MouseEvent evt) {
                ingdTableMouseClicked(evt);
            }
        });
        ingdTable.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                ingdTableKeyPressed(evt);
            }
        });
        jScrollPane3.setViewportView(ingdTable);

        jPanel1.add(jScrollPane3, java.awt.BorderLayout.CENTER);

        jPanel4.setName("jPanel4"); // NOI18N

        newIngd.setMnemonic('N');
        newIngd.setText(resourceMap.getString("newIngd.text")); // NOI18N
        newIngd.setName("newIngd"); // NOI18N
        newIngd.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                newIngdActionPerformed(evt);
            }
        });
        jPanel4.add(newIngd);

        delIngd.setMnemonic('D');
        delIngd.setText(resourceMap.getString("delIngd.text")); // NOI18N
        delIngd.setName("delIngd"); // NOI18N
        delIngd.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                delIngdActionPerformed(evt);
            }
        });
        jPanel4.add(delIngd);

        jPanel1.add(jPanel4, java.awt.BorderLayout.PAGE_END);

        jTabbedPane1.addTab(resourceMap.getString("jPanel1.TabConstraints.tabTitle"), jPanel1); // NOI18N

        jPanel2.setName("jPanel2"); // NOI18N
        jPanel2.setLayout(new java.awt.BorderLayout());

        jScrollPane2.setName("jScrollPane2"); // NOI18N

        recipeText.setBackground(resourceMap.getColor("recipeText.background")); // NOI18N
        recipeText.setFont(resourceMap.getFont("recipeText.font")); // NOI18N
        recipeText.setText(resourceMap.getString("recipeText.text")); // NOI18N
        recipeText.setName("recipeText"); // NOI18N
        jScrollPane2.setViewportView(recipeText);

        jPanel2.add(jScrollPane2, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab(resourceMap.getString("jPanel2.TabConstraints.tabTitle"), jPanel2); // NOI18N

        jPanel3.setName("jPanel3"); // NOI18N
        jPanel3.setLayout(new java.awt.BorderLayout());

        jScrollPane4.setName("jScrollPane4"); // NOI18N

        simpleIngd.setBackground(resourceMap.getColor("simpleIngd.background")); // NOI18N
        simpleIngd.setContentType(resourceMap.getString("simpleIngd.contentType")); // NOI18N
        simpleIngd.setEditable(false);
        simpleIngd.setName("simpleIngd"); // NOI18N
        simpleIngd.addHyperlinkListener(new javax.swing.event.HyperlinkListener() {
            public void hyperlinkUpdate(javax.swing.event.HyperlinkEvent evt) {
                simpleIngdHyperlinkUpdate(evt);
            }
        });
        jScrollPane4.setViewportView(simpleIngd);

        jPanel3.add(jScrollPane4, java.awt.BorderLayout.CENTER);

        jTabbedPane1.addTab(resourceMap.getString("jPanel3.TabConstraints.tabTitle"), jPanel3); // NOI18N

        jPanel5.setName("jPanel5"); // NOI18N
        jPanel5.setOpaque(false);

        jLabel8.setBackground(resourceMap.getColor("jLabel8.background")); // NOI18N
        jLabel8.setForeground(resourceMap.getColor("jLabel8.foreground")); // NOI18N
        jLabel8.setText(resourceMap.getString("jLabel8.text")); // NOI18N
        jLabel8.setName("jLabel8"); // NOI18N
        jLabel8.setOpaque(true);

        jScrollPane1.setName("jScrollPane1"); // NOI18N

        bakerNotes.setColumns(20);
        bakerNotes.setRows(5);
        bakerNotes.setName("bakerNotes"); // NOI18N
        jScrollPane1.setViewportView(bakerNotes);

        javax.swing.GroupLayout jPanel5Layout = new javax.swing.GroupLayout(jPanel5);
        jPanel5.setLayout(jPanel5Layout);
        jPanel5Layout.setHorizontalGroup(
            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel5Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 389, Short.MAX_VALUE)
                    .addComponent(jLabel8, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap())
        );
        jPanel5Layout.setVerticalGroup(
            jPanel5Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel5Layout.createSequentialGroup()
                .addContainerGap()
                .addComponent(jLabel8, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addGap(9, 9, 9)
                .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 189, Short.MAX_VALUE)
                .addContainerGap())
        );

        jPanel6.setName("jPanel6"); // NOI18N
        jPanel6.setOpaque(false);

        jLabel5.setBackground(resourceMap.getColor("jLabel7.background")); // NOI18N
        jLabel5.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel5.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel5.setText(resourceMap.getString("jLabel5.text")); // NOI18N
        jLabel5.setMinimumSize(new java.awt.Dimension(112, 15));
        jLabel5.setName("jLabel5"); // NOI18N
        jLabel5.setOpaque(true);

        source.setHorizontalAlignment(javax.swing.JTextField.LEFT);
        source.setText(resourceMap.getString("source.text")); // NOI18N
        source.setName("source"); // NOI18N

        cookingTime.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        cookingTime.setText(resourceMap.getString("cookingTime.text")); // NOI18N
        cookingTime.setName("cookingTime"); // NOI18N

        jLabel3.setBackground(resourceMap.getColor("jLabel7.background")); // NOI18N
        jLabel3.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel3.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel3.setText(resourceMap.getString("jLabel3.text")); // NOI18N
        jLabel3.setName("jLabel3"); // NOI18N
        jLabel3.setOpaque(true);

        preparationTime.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        preparationTime.setText(resourceMap.getString("preparationTime.text")); // NOI18N
        preparationTime.setName("preparationTime"); // NOI18N

        jLabel2.setBackground(resourceMap.getColor("jLabel7.background")); // NOI18N
        jLabel2.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel2.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel2.setText(resourceMap.getString("jLabel2.text")); // NOI18N
        jLabel2.setName("jLabel2"); // NOI18N
        jLabel2.setOpaque(true);

        readyIn.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        readyIn.setText(resourceMap.getString("readyIn.text")); // NOI18N
        readyIn.setName("readyIn"); // NOI18N

        jLabel4.setBackground(resourceMap.getColor("jLabel7.background")); // NOI18N
        jLabel4.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel4.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel4.setText(resourceMap.getString("jLabel4.text")); // NOI18N
        jLabel4.setName("jLabel4"); // NOI18N
        jLabel4.setOpaque(true);

        javax.swing.GroupLayout jPanel6Layout = new javax.swing.GroupLayout(jPanel6);
        jPanel6.setLayout(jPanel6Layout);
        jPanel6Layout.setHorizontalGroup(
            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel6Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel2)
                    .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, 112, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(jLabel4, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addComponent(jLabel3, javax.swing.GroupLayout.Alignment.LEADING)))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(preparationTime, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(cookingTime, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(readyIn, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(source, javax.swing.GroupLayout.PREFERRED_SIZE, 313, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel6Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel2, jLabel3, jLabel4, jLabel5});

        jPanel6Layout.setVerticalGroup(
            jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel6Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel6Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel6Layout.createSequentialGroup()
                        .addComponent(preparationTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(cookingTime, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(readyIn, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(source, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(jLabel2)
                    .addGroup(jPanel6Layout.createSequentialGroup()
                        .addGap(26, 26, 26)
                        .addComponent(jLabel3)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jLabel4))
                    .addGroup(jPanel6Layout.createSequentialGroup()
                        .addGap(79, 79, 79)
                        .addComponent(jLabel5, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel6Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {cookingTime, jLabel2, jLabel3, jLabel4, jLabel5, preparationTime, readyIn, source});

        jPanel7.setName("jPanel7"); // NOI18N
        jPanel7.setOpaque(false);

        jLabel10.setBackground(resourceMap.getColor("jLabel10.background")); // NOI18N
        jLabel10.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel10.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel10.setText(resourceMap.getString("jLabel10.text")); // NOI18N
        jLabel10.setName("jLabel10"); // NOI18N
        jLabel10.setOpaque(true);

        jLabel9.setBackground(resourceMap.getColor("jLabel9.background")); // NOI18N
        jLabel9.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel9.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel9.setText(resourceMap.getString("jLabel9.text")); // NOI18N
        jLabel9.setName("jLabel9"); // NOI18N
        jLabel9.setOpaque(true);

        actFlourWeight.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        actFlourWeight.setText(resourceMap.getString("actFlourWeight.text")); // NOI18N
        actFlourWeight.setName("actFlourWeight"); // NOI18N
        actFlourWeight.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                actFlourWeightActionPerformed(evt);
            }
        });

        jLabel11.setBackground(resourceMap.getColor("jLabel11.background")); // NOI18N
        jLabel11.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel11.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel11.setText(resourceMap.getString("jLabel11.text")); // NOI18N
        jLabel11.setName("jLabel11"); // NOI18N
        jLabel11.setOpaque(true);

        hydLevel.setEditable(false);
        hydLevel.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        hydLevel.setText(resourceMap.getString("hydLevel.text")); // NOI18N
        hydLevel.setName("hydLevel"); // NOI18N

        flourWeight.setEditable(false);
        flourWeight.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        flourWeight.setText(resourceMap.getString("flourWeight.text")); // NOI18N
        flourWeight.setName("flourWeight"); // NOI18N

        javax.swing.GroupLayout jPanel7Layout = new javax.swing.GroupLayout(jPanel7);
        jPanel7.setLayout(jPanel7Layout);
        jPanel7Layout.setHorizontalGroup(
            jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel7Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jLabel11)
                    .addComponent(jLabel9)
                    .addComponent(jLabel10))
                .addGap(18, 18, 18)
                .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(actFlourWeight, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(flourWeight, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(hydLevel, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel7Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel10, jLabel11, jLabel9});

        jPanel7Layout.setVerticalGroup(
            jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel7Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(flourWeight, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel9))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(hydLevel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel10))
                .addGap(10, 10, 10)
                .addGroup(jPanel7Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel11)
                    .addComponent(actFlourWeight, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel7Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {actFlourWeight, flourWeight, hydLevel, jLabel10, jLabel11, jLabel9});

        jPanel8.setName("jPanel8"); // NOI18N
        jPanel8.setOpaque(false);

        servingWeight.setEditable(false);
        servingWeight.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        servingWeight.setText(resourceMap.getString("servingWeight.text")); // NOI18N
        servingWeight.setName("servingWeight"); // NOI18N

        jLabel16.setBackground(resourceMap.getColor("jLabel16.background")); // NOI18N
        jLabel16.setFont(resourceMap.getFont("jLabel16.font")); // NOI18N
        jLabel16.setForeground(resourceMap.getColor("jLabel16.foreground")); // NOI18N
        jLabel16.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel16.setText(resourceMap.getString("jLabel16.text")); // NOI18N
        jLabel16.setName("jLabel16"); // NOI18N
        jLabel16.setOpaque(true);

        costPerServing.setEditable(false);
        costPerServing.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        costPerServing.setText(resourceMap.getString("costPerServing.text")); // NOI18N
        costPerServing.setName("costPerServing"); // NOI18N

        totalCost.setEditable(false);
        totalCost.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        totalCost.setText(resourceMap.getString("totalCost.text")); // NOI18N
        totalCost.setName("totalCost"); // NOI18N

        jLabel18.setBackground(resourceMap.getColor("jLabel18.background")); // NOI18N
        jLabel18.setFont(resourceMap.getFont("jLabel18.font")); // NOI18N
        jLabel18.setForeground(resourceMap.getColor("jLabel18.foreground")); // NOI18N
        jLabel18.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel18.setText(resourceMap.getString("jLabel18.text")); // NOI18N
        jLabel18.setName("jLabel18"); // NOI18N
        jLabel18.setOpaque(true);

        jLabel12.setBackground(resourceMap.getColor("jLabel12.background")); // NOI18N
        jLabel12.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel12.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel12.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel12.setText(resourceMap.getString("jLabel12.text")); // NOI18N
        jLabel12.setName("jLabel12"); // NOI18N
        jLabel12.setOpaque(true);

        jLabel13.setBackground(resourceMap.getColor("jLabel13.background")); // NOI18N
        jLabel13.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel13.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel13.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel13.setText(resourceMap.getString("jLabel13.text")); // NOI18N
        jLabel13.setName("jLabel13"); // NOI18N
        jLabel13.setOpaque(true);

        calPerSrv.setEditable(false);
        calPerSrv.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        calPerSrv.setText(resourceMap.getString("calPerSrv.text")); // NOI18N
        calPerSrv.setName("calPerSrv"); // NOI18N

        totalCalories.setEditable(false);
        totalCalories.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        totalCalories.setText(resourceMap.getString("totalCalories.text")); // NOI18N
        totalCalories.setName("totalCalories"); // NOI18N

        totalWeight.setEditable(false);
        totalWeight.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        totalWeight.setText(resourceMap.getString("totalWeight.text")); // NOI18N
        totalWeight.setName("totalWeight"); // NOI18N

        jLabel14.setBackground(resourceMap.getColor("jLabel14.background")); // NOI18N
        jLabel14.setFont(resourceMap.getFont("jLabel9.font")); // NOI18N
        jLabel14.setForeground(resourceMap.getColor("jLabel9.foreground")); // NOI18N
        jLabel14.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
        jLabel14.setText(resourceMap.getString("jLabel14.text")); // NOI18N
        jLabel14.setName("jLabel14"); // NOI18N
        jLabel14.setOpaque(true);

        javax.swing.GroupLayout jPanel8Layout = new javax.swing.GroupLayout(jPanel8);
        jPanel8.setLayout(jPanel8Layout);
        jPanel8Layout.setHorizontalGroup(
            jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel8Layout.createSequentialGroup()
                .addGap(30, 30, 30)
                .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(jLabel13, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(jLabel14, javax.swing.GroupLayout.PREFERRED_SIZE, 54, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jLabel16, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(servingWeight, javax.swing.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE)
                    .addComponent(totalWeight, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(18, 18, 18)
                .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addComponent(jLabel18, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(totalCalories, javax.swing.GroupLayout.DEFAULT_SIZE, 81, Short.MAX_VALUE)
                    .addComponent(calPerSrv, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(totalCost, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(costPerServing, javax.swing.GroupLayout.PREFERRED_SIZE, 81, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel12, javax.swing.GroupLayout.PREFERRED_SIZE, 80, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );
        jPanel8Layout.setVerticalGroup(
            jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel8Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel8Layout.createSequentialGroup()
                        .addComponent(jLabel16)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(servingWeight, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel14))
                        .addGap(4, 4, 4)
                        .addGroup(jPanel8Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                            .addComponent(totalWeight, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel13)))
                    .addGroup(jPanel8Layout.createSequentialGroup()
                        .addComponent(jLabel18)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(calPerSrv, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(4, 4, 4)
                        .addComponent(totalCalories, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addGroup(jPanel8Layout.createSequentialGroup()
                        .addComponent(jLabel12)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(costPerServing, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addGap(4, 4, 4)
                        .addComponent(totalCost, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                .addContainerGap(12, Short.MAX_VALUE))
        );

        jPanel8Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {calPerSrv, costPerServing, jLabel12, jLabel13, jLabel14, jLabel16, jLabel18, servingWeight, totalCalories, totalCost, totalWeight});

        jPanel9.setName("jPanel9"); // NOI18N
        jPanel9.setOpaque(false);

        jLabel7.setBackground(resourceMap.getColor("jLabel7.background")); // NOI18N
        jLabel7.setForeground(resourceMap.getColor("jLabel7.foreground")); // NOI18N
        jLabel7.setText(resourceMap.getString("jLabel7.text")); // NOI18N
        jLabel7.setName("jLabel7"); // NOI18N
        jLabel7.setOpaque(true);

        yield.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        yield.setText(resourceMap.getString("yield.text")); // NOI18N
        yield.setName("yield"); // NOI18N

        jLabel6.setBackground(resourceMap.getColor("jLabel7.background")); // NOI18N
        jLabel6.setForeground(resourceMap.getColor("jLabel7.foreground")); // NOI18N
        jLabel6.setText(resourceMap.getString("jLabel6.text")); // NOI18N
        jLabel6.setName("jLabel6"); // NOI18N
        jLabel6.setOpaque(true);

        jLabel15.setBackground(resourceMap.getColor("jLabel15.background")); // NOI18N
        jLabel15.setFont(resourceMap.getFont("jLabel15.font")); // NOI18N
        jLabel15.setForeground(resourceMap.getColor("jLabel15.foreground")); // NOI18N
        jLabel15.setText(resourceMap.getString("jLabel15.text")); // NOI18N
        jLabel15.setName("jLabel15"); // NOI18N
        jLabel15.setOpaque(true);

        servings.setModel(new javax.swing.SpinnerNumberModel(Integer.valueOf(12), Integer.valueOf(1), null, Integer.valueOf(1)));
        servings.setName("servings"); // NOI18N
        servings.setOpaque(false);
        servings.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                servingsStateChanged(evt);
            }
        });

        resizeFactor.setBackground(resourceMap.getColor("resizeFactor.background")); // NOI18N
        resizeFactor.setHorizontalAlignment(javax.swing.JTextField.RIGHT);
        resizeFactor.setText(resourceMap.getString("resizeFactor.text")); // NOI18N
        resizeFactor.setName("resizeFactor"); // NOI18N
        resizeFactor.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                resizeFactorActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout jPanel9Layout = new javax.swing.GroupLayout(jPanel9);
        jPanel9.setLayout(jPanel9Layout);
        jPanel9Layout.setHorizontalGroup(
            jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel9Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(jPanel9Layout.createSequentialGroup()
                        .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel15)
                            .addComponent(jLabel7))
                        .addGap(9, 9, 9)
                        .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(resizeFactor)
                            .addComponent(yield, javax.swing.GroupLayout.PREFERRED_SIZE, 135, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addGroup(jPanel9Layout.createSequentialGroup()
                        .addComponent(jLabel6)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addComponent(servings)))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel9Layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {jLabel15, jLabel6, jLabel7});

        jPanel9Layout.setVerticalGroup(
            jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel9Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(servings, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel6))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(yield, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel7))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel9Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(resizeFactor, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel15))
                .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        );

        jPanel9Layout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {jLabel15, jLabel6, jLabel7, resizeFactor, servings, yield});

        javax.swing.GroupLayout mainPanelLayout = new javax.swing.GroupLayout(mainPanel);
        mainPanel.setLayout(mainPanelLayout);
        mainPanelLayout.setHorizontalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                    .addComponent(jTabbedPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 1134, Short.MAX_VALUE)
                    .addGroup(mainPanelLayout.createSequentialGroup()
                        .addContainerGap()
                        .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(recipeTitle, javax.swing.GroupLayout.DEFAULT_SIZE, 1124, Short.MAX_VALUE)
                            .addGroup(mainPanelLayout.createSequentialGroup()
                                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                    .addGroup(mainPanelLayout.createSequentialGroup()
                                        .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                        .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                                    .addGroup(mainPanelLayout.createSequentialGroup()
                                        .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                        .addComponent(jPanel8, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)))
                                .addGap(18, 18, 18)
                                .addComponent(jPanel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))))
                .addContainerGap())
        );
        mainPanelLayout.setVerticalGroup(
            mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(mainPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(recipeTitle, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jPanel5, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, mainPanelLayout.createSequentialGroup()
                        .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jPanel6, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jPanel9, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                        .addGroup(mainPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
                            .addComponent(jPanel7, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jPanel8, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addGap(18, 18, 18)
                .addComponent(jTabbedPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 379, Short.MAX_VALUE)
                .addContainerGap())
        );

        jTabbedPane1.getAccessibleContext().setAccessibleName(resourceMap.getString("jTabbedPane1.AccessibleContext.accessibleName")); // NOI18N

        menuBar.setName("menuBar"); // NOI18N

        fileMenu.setText(resourceMap.getString("fileMenu.text")); // NOI18N
        fileMenu.setName("fileMenu"); // NOI18N
        fileMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                fileMenuActionPerformed(evt);
            }
        });

        jMenuItem2.setText(resourceMap.getString("jMenuItem2.text")); // NOI18N
        jMenuItem2.setName("jMenuItem2"); // NOI18N
        jMenuItem2.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem2ActionPerformed(evt);
            }
        });
        fileMenu.add(jMenuItem2);

        jOpenRec.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_O, java.awt.event.InputEvent.CTRL_MASK));
        jOpenRec.setMnemonic('O');
        jOpenRec.setText(resourceMap.getString("jOpenRec.text")); // NOI18N
        jOpenRec.setName("jOpenRec"); // NOI18N
        jOpenRec.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jOpenRecActionPerformed(evt);
            }
        });
        fileMenu.add(jOpenRec);

        jSaveRec.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_S, java.awt.event.InputEvent.CTRL_MASK));
        jSaveRec.setText(resourceMap.getString("jSaveRec.text")); // NOI18N
        jSaveRec.setName("jSaveRec"); // NOI18N
        jSaveRec.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jSaveRecActionPerformed(evt);
            }
        });
        fileMenu.add(jSaveRec);

        saveAs.setText(resourceMap.getString("saveAs.text")); // NOI18N
        saveAs.setName("saveAs"); // NOI18N
        saveAs.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                saveAsActionPerformed(evt);
            }
        });
        fileMenu.add(saveAs);

        loadIngdMenu.setText(resourceMap.getString("loadIngdMenu.text")); // NOI18N
        loadIngdMenu.setName("loadIngdMenu"); // NOI18N
        loadIngdMenu.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                loadIngdMenuActionPerformed(evt);
            }
        });
        fileMenu.add(loadIngdMenu);

        javax.swing.ActionMap actionMap = org.jdesktop.application.Application.getInstance(simplerecipes.SimpleRecipesApp.class).getContext().getActionMap(SimpleRecipesView.class, this);
        exitMenuItem.setAction(actionMap.get("quit")); // NOI18N
        exitMenuItem.setName("exitMenuItem"); // NOI18N
        fileMenu.add(exitMenuItem);

        menuBar.add(fileMenu);

        jMenu1.setText(resourceMap.getString("jMenu1.text")); // NOI18N
        jMenu1.setName("jMenu1"); // NOI18N

        jMenu2.setText(resourceMap.getString("jMenu2.text")); // NOI18N
        jMenu2.setName("jMenu2"); // NOI18N
        jMenu2.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                jMenu2StateChanged(evt);
            }
        });

        mQuantity.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_Q, java.awt.event.InputEvent.CTRL_MASK));
        buttonGroup1.add(mQuantity);
        mQuantity.setSelected(true);
        mQuantity.setText(resourceMap.getString("mQuantity.text")); // NOI18N
        mQuantity.setName("mQuantity"); // NOI18N
        mQuantity.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                mQuantityStateChanged(evt);
            }
        });
        jMenu2.add(mQuantity);

        mPercentage.setAccelerator(javax.swing.KeyStroke.getKeyStroke(java.awt.event.KeyEvent.VK_P, java.awt.event.InputEvent.CTRL_MASK));
        buttonGroup1.add(mPercentage);
        mPercentage.setText(resourceMap.getString("mPercentage.text")); // NOI18N
        mPercentage.setName("mPercentage"); // NOI18N
        mPercentage.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                mPercentageStateChanged(evt);
            }
        });
        jMenu2.add(mPercentage);

        jMenu1.add(jMenu2);

        jMenu3.setText(resourceMap.getString("jMenu3.text")); // NOI18N
        jMenu3.setName("jMenu3"); // NOI18N

        unitGroup.add(gUnit);
        gUnit.setSelected(true);
        gUnit.setText(resourceMap.getString("gUnit.text")); // NOI18N
        gUnit.setName("gUnit"); // NOI18N
        gUnit.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                gUnitStateChanged(evt);
            }
        });
        gUnit.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                gUnitActionPerformed(evt);
            }
        });
        jMenu3.add(gUnit);

        unitGroup.add(kgUnit);
        kgUnit.setText(resourceMap.getString("kgUnit.text")); // NOI18N
        kgUnit.setName("kgUnit"); // NOI18N
        kgUnit.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                kgUnitStateChanged(evt);
            }
        });
        jMenu3.add(kgUnit);

        unitGroup.add(ozUnit);
        ozUnit.setText(resourceMap.getString("ozUnit.text")); // NOI18N
        ozUnit.setName("ozUnit"); // NOI18N
        ozUnit.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                ozUnitStateChanged(evt);
            }
        });
        jMenu3.add(ozUnit);

        unitGroup.add(lbUnit);
        lbUnit.setText(resourceMap.getString("lbUnit.text")); // NOI18N
        lbUnit.setName("lbUnit"); // NOI18N
        lbUnit.addChangeListener(new javax.swing.event.ChangeListener() {
            public void stateChanged(javax.swing.event.ChangeEvent evt) {
                lbUnitStateChanged(evt);
            }
        });
        jMenu3.add(lbUnit);

        jMenu1.add(jMenu3);

        jMenuItem1.setText(resourceMap.getString("jMenuItem1.text")); // NOI18N
        jMenuItem1.setName("jMenuItem1"); // NOI18N
        jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                jMenuItem1ActionPerformed(evt);
            }
        });
        jMenu1.add(jMenuItem1);

        menuBar.add(jMenu1);

        helpMenu.setText(resourceMap.getString("helpMenu.text")); // NOI18N
        helpMenu.setName("helpMenu"); // NOI18N

        aboutMenuItem.setAction(actionMap.get("showAboutBox")); // NOI18N
        aboutMenuItem.setName("aboutMenuItem"); // NOI18N
        helpMenu.add(aboutMenuItem);

        menuBar.add(helpMenu);

        statusPanel.setName("statusPanel"); // NOI18N

        statusPanelSeparator.setName("statusPanelSeparator"); // NOI18N

        statusMessageLabel.setName("statusMessageLabel"); // NOI18N

        statusAnimationLabel.setHorizontalAlignment(javax.swing.SwingConstants.LEFT);
        statusAnimationLabel.setName("statusAnimationLabel"); // NOI18N

        progressBar.setName("progressBar"); // NOI18N

        javax.swing.GroupLayout statusPanelLayout = new javax.swing.GroupLayout(statusPanel);
        statusPanel.setLayout(statusPanelLayout);
        statusPanelLayout.setHorizontalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(statusPanelSeparator, javax.swing.GroupLayout.DEFAULT_SIZE, 1144, Short.MAX_VALUE)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addContainerGap()
                .addComponent(statusMessageLabel)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 974, Short.MAX_VALUE)
                .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(statusAnimationLabel)
                .addContainerGap())
        );
        statusPanelLayout.setVerticalGroup(
            statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(statusPanelLayout.createSequentialGroup()
                .addComponent(statusPanelSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 2, javax.swing.GroupLayout.PREFERRED_SIZE)
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                .addGroup(statusPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(statusMessageLabel)
                    .addComponent(statusAnimationLabel)
                    .addComponent(progressBar, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(3, 3, 3))
        );

        setComponent(mainPanel);
        setMenuBar(menuBar);
        setStatusBar(statusPanel);
    }// </editor-fold>//GEN-END:initComponents

    private void fileMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileMenuActionPerformed
        // TODO add your handling code here:
    }//GEN-LAST:event_fileMenuActionPerformed

    private void jOpenRecActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jOpenRecActionPerformed
      if(openedFile != null) {
            Object[] options = {"Yes, please",
                "No way!"};
            int n = JOptionPane.showOptionDialog(getFrame(),
                    "Do you want to save the current recipe?",
                    "Save Recipe",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null, //do not use a custom Icon
                    options, //the titles of buttons
                    options[0]); //default button title

            if (n == JOptionPane.OK_OPTION) {
                saveCurrentRecipe();
            }
        }

        int returnVal = fc.showOpenDialog(null);
        if (returnVal == JFileChooser.APPROVE_OPTION) {
            openedFile = fc.getSelectedFile().getAbsolutePath();
            Properties rprop = new Properties();
            try {
                rprop.load(new FileInputStream(openedFile));
            } catch (IOException ex) {
                Logger.getLogger(SimpleRecipesView.class.getName()).log(Level.SEVERE, null, ex);
            }
            
            this.recipe.setName(rprop.getProperty("name"));
            recipe.setPreTime(rprop.getProperty("Preparation_Time"));
            recipe.setCookingTime(rprop.getProperty("Cooking_Time"));
            recipe.setReadyIn(rprop.getProperty("Ready_In"));
            recipe.setSource(rprop.getProperty("Source"));
            recipe.setServings(Integer.parseInt(rprop.getProperty("Servings")));
            recipe.setYield(rprop.getProperty("Yield"));
            recipe.setResizeFactor(Double.parseDouble(rprop.getProperty("Resize_Factor")));
            recipe.setActualFlourWeight(Double.parseDouble(rprop.getProperty("Actual_Flour_Weight")));
            recipe.setBakerNotes(rprop.getProperty("Baker_Notes"));
            recipe.setRecipe(rprop.getProperty("Recipe"));
            recipe.setUnit(Unit.valueOf(rprop.getProperty("Unit")));
            recipe.setMeasurementType(MeasurementType.valueOf(rprop.getProperty("Measurement_Type")));
            
            recipe.getIngredients().clear();
            String sgmt[] = null;
            int count = Integer.parseInt(rprop.getProperty("Ingredients_Size"));
            for(int i = 0; i < count; i++) {
                //System.out.println((String) rprop.get("Ingredients_" + i));
                sgmt = ((String) rprop.get("Ingredients_" + i)).split("!");
                //for(int j = 0; j < sgmt.length; j++)
                //    System.out.println("sgmt[" + j + "]=" + sgmt[j]);
                recipe.addIngredient(new MesuredIngredient(
                        findIngredientByID(Integer.parseInt(sgmt[0]))));
                recipe.getIngredients().get(i).setQuantity(Double.parseDouble(sgmt[1]));
                recipe.getIngredients().get(i).setUnit(Unit.valueOf(sgmt[2]));
                if(sgmt.length > 3)
                    recipe.getIngredients().get(i).setDetails(sgmt[3]);
            }
            
            recipeChanged();
        
        } else {
            System.out.println("Nothing Selected");
        }
    }//GEN-LAST:event_jOpenRecActionPerformed

    private void servingsStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_servingsStateChanged
        if (recipe != null) {
            recipe.setServings((Integer) servings.getValue());
        }
    }//GEN-LAST:event_servingsStateChanged

    private void jTabbedPane1FocusGained(java.awt.event.FocusEvent evt) {//GEN-FIRST:event_jTabbedPane1FocusGained
   
    }//GEN-LAST:event_jTabbedPane1FocusGained

    private void jTabbedPane1StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jTabbedPane1StateChanged
        // TODO add your handling code here:
//        System.out.println(((JTabbedPane) evt.getSource()).getSelectedIndex());
        if ( ((JTabbedPane) evt.getSource()).getSelectedIndex() == 2){ 
            updateHTMLDetails();
        }
    }//GEN-LAST:event_jTabbedPane1StateChanged

    private String fixRecipeLine(String line) {
        if(line.contains("<img")) {
            String regexp = "<img\\s+src=\\\"(.*?)\\\"\\s*/?>";
            String link = line.replaceAll(regexp, "$1");
            line = line.replace(link, ResourcesLoader.getInstance().getResourcePathForWeb(link));
            System.out.println(line + " --> " + link);
            //return line;
        } else if(line.contains("<a ")) {
            int s1 = line.indexOf("href") + 6;
            int s2 = line.indexOf("\"", s1);
            String link = line.substring(s1, s2);
            line = line.replace(link, ResourcesLoader.getInstance().getResourcePathForWeb(link));
            System.out.println(line + " --> " + link);
            //return line;
        }
        
        return "<p>" + line + "<br/>";
    }
    private void mQuantityStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_mQuantityStateChanged
        if(recipe != null && mQuantity.isSelected()) {
            recipe.setMeasurementType(MeasurementType.QUANTITY);
        }
    }//GEN-LAST:event_mQuantityStateChanged

    private void mPercentageStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_mPercentageStateChanged
        if(recipe != null && mPercentage.isSelected()) {
            recipe.setMeasurementType(MeasurementType.PERCENTAGE);
        }
    }//GEN-LAST:event_mPercentageStateChanged

    private void jMenu2StateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_jMenu2StateChanged
    }//GEN-LAST:event_jMenu2StateChanged

    private void actFlourWeightActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_actFlourWeightActionPerformed
        try {
            double afw = Double.parseDouble(actFlourWeight.getText());
            if(recipe != null) {
                recipe.setActualFlourWeight(afw * recipe.getToGramFactor());
                ((IngredientTableModel) ingdTable.getModel()).updateAll();
            }
        } catch(NumberFormatException nfe) {
            JOptionPane.showMessageDialog(null, actFlourWeight.getText() + " is not a number!", 
                    "Number format error!", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_actFlourWeightActionPerformed

    private void resizeFactorActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_resizeFactorActionPerformed
        try {
            double rf = Double.parseDouble(resizeFactor.getText());
            if(recipe != null) {
                recipe.setResizeFactor(rf);
                ((IngredientTableModel) ingdTable.getModel()).updateAll();
                servings.setValue((int) (((Integer) servings.getValue()) * rf * 1/oldResizeFactor));
            }
            oldResizeFactor = rf;
        } catch(NumberFormatException nfe) {
            JOptionPane.showMessageDialog(null, resizeFactor.getText() + " is not a number!", 
                    "Number format error!", JOptionPane.ERROR_MESSAGE);
        }
    }//GEN-LAST:event_resizeFactorActionPerformed

    private void gUnitActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_gUnitActionPerformed

    }//GEN-LAST:event_gUnitActionPerformed

    private void kgUnitStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_kgUnitStateChanged
        if(kgUnit.isSelected()) {
            unitChanged(Unit.kg);
        }
    }//GEN-LAST:event_kgUnitStateChanged

    private void gUnitStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_gUnitStateChanged
        if(gUnit.isSelected()) {
            unitChanged(Unit.g);
        }
    }//GEN-LAST:event_gUnitStateChanged

    private void ozUnitStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_ozUnitStateChanged
        if(ozUnit.isSelected()) {
            unitChanged(Unit.oz);
        }
    }//GEN-LAST:event_ozUnitStateChanged

    private void lbUnitStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_lbUnitStateChanged
        if(lbUnit.isSelected()) {
            unitChanged(Unit.lb);
        }
    }//GEN-LAST:event_lbUnitStateChanged

    private void recipeTitleMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_recipeTitleMouseClicked
        if (evt.getClickCount() == 2 && !evt.isConsumed()) {
            evt.consume();
            String title = JOptionPane.showInputDialog("Recipe title:", recipe.getName());
            if(title != null) {
                recipe.setName(title);
                updateRecipeTitle(title);
            }
        }
    }//GEN-LAST:event_recipeTitleMouseClicked

    private void loadIngdMenuActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_loadIngdMenuActionPerformed
        int returnVal = fc.showOpenDialog(null);

        if (returnVal == JFileChooser.APPROVE_OPTION) {
            ingdFile = fc.getSelectedFile();
            loadIngredients(ingdFile);
            ((IngredientTableModel) ingdTable.getModel()).updateAll();
        } else {
            System.out.println("Nothing Selected");
        }
    }//GEN-LAST:event_loadIngdMenuActionPerformed

    private void jSaveRecActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jSaveRecActionPerformed
        saveCurrentRecipe();
    }//GEN-LAST:event_jSaveRecActionPerformed

    private void newIngdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newIngdActionPerformed
        recipe.addIngredient(new MesuredIngredient(findIngredientByID(100)));
        ingdTable.setValueAt(Unit.tsp, recipe.getIngredients().size() -1 , 2);        
        ingdTable.setValueAt(1.0, recipe.getIngredients().size() -1 , 1);
    }//GEN-LAST:event_newIngdActionPerformed

    private void delIngdActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_delIngdActionPerformed
        int rows[] = ingdTable.getSelectedRows();
        if(rows.length > 0) {
            for(int i = rows.length -1; i >= 0; i--)
                recipe.getIngredients().remove(rows[i]);
        }
        ((IngredientTableModel)  ingdTable.getModel()).updateAll();
    }//GEN-LAST:event_delIngdActionPerformed

    private void jMenuItem2ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem2ActionPerformed
      if(openedFile != null) {
            Object[] options = {"Yes, please",
                "No way!"};
            int n = JOptionPane.showOptionDialog(getFrame(),
                    "Do you want to save the current recipe?",
                    "Save Recipe",
                    JOptionPane.YES_NO_OPTION,
                    JOptionPane.QUESTION_MESSAGE,
                    null, //do not use a custom Icon
                    options, //the titles of buttons
                    options[0]); //default button title

            if (n == JOptionPane.OK_OPTION) {
                saveCurrentRecipe();
            }
        }
      
      
        recipe.setName("New Recipe");
        updateRecipeTitle(recipe.getName());
        recipe.setPreTime("15 min");
        recipe.setCookingTime("35 min");
        recipe.setReadyIn("4 hrs");
        recipe.setSource("source");
        recipe.setServings(12);
        recipe.setYield("2 Small loaves");
        recipe.setResizeFactor(1.0);
        recipe.setActualFlourWeight(0.0, true);
        recipe.setBakerNotes("");
        recipe.setRecipe("");
        
        recipe.getIngredients().clear();
        recipeChanged();
        openedFile = null;
    }//GEN-LAST:event_jMenuItem2ActionPerformed

    private void ingdTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_ingdTableMouseClicked
        if (evt.getComponent().isEnabled() && 
                evt.getButton() == MouseEvent.BUTTON1 &&
                evt.getClickCount() == 2) {
            Point p = evt.getPoint();
            int row = ingdTable.rowAtPoint(p); 
            int column = ingdTable.columnAtPoint(p); 
            
            
            if(column == 4) { //weight
                IngredientTableModel model = (IngredientTableModel) ingdTable.getModel();
                
                double weight = Double.parseDouble(JOptionPane.showInputDialog(
                        "Weight:", model.getValueAt(row, column)));
                double ingdWeight = Double.parseDouble((String) model.getValueAt(row, 6));
                model.setValueAt(weight/ingdWeight, row, 1);
            }
        }
    }//GEN-LAST:event_ingdTableMouseClicked

    private void ingdTableKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_ingdTableKeyPressed
        if(evt.getKeyCode() == KeyEvent.VK_F2) {
            int row = ingdTable.getSelectedRow();
            if(row != -1) {
                String rVal = JOptionPane.showInputDialog(null, 
                        "Ingredient Name:", 
                        recipe.getIngredients().get(row).getDetails());
                
                if(rVal != null) {
                    recipe.getIngredients().get(row).setDetails(rVal);
                    ((IngredientTableModel)  ingdTable.getModel()).updateAll();
                }
            }
        }
    }//GEN-LAST:event_ingdTableKeyPressed

    private void simpleIngdHyperlinkUpdate(javax.swing.event.HyperlinkEvent evt) {//GEN-FIRST:event_simpleIngdHyperlinkUpdate
        try {
            if (evt.getEventType() == HyperlinkEvent.EventType.ACTIVATED) {

                String link = evt.getURL().toString();
                System.out.println(link);
                if (link.startsWith("file")) {
                    System.out.println(link.substring(6));
                    Desktop.getDesktop().open(new File(link.substring(6)));
                } else {
                    Desktop.getDesktop().browse(evt.getURL().toURI());
                }
            }
        } catch (IOException ex) {
            Logger.getLogger(SimpleRecipesView.class.getName()).log(Level.SEVERE, null, ex);
        } catch (URISyntaxException ex) {
            Logger.getLogger(SimpleRecipesView.class.getName()).log(Level.SEVERE, null, ex);
        }
    }//GEN-LAST:event_simpleIngdHyperlinkUpdate

    private void jMenuItem1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jMenuItem1ActionPerformed
        if(ingdFile != null) {
            loadIngredients(ingdFile);
            ((IngredientTableModel) ingdTable.getModel()).updateAll();
        }
    }//GEN-LAST:event_jMenuItem1ActionPerformed

    private void saveAsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveAsActionPerformed
        String tmp = openedFile;
        if(openedFile != null) {
            saveCurrentRecipe();
            openedFile = null;
        }
        saveCurrentRecipe();
        if(openedFile == null) {
            openedFile = tmp;
        }
    }//GEN-LAST:event_saveAsActionPerformed

    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JTextField actFlourWeight;
    private javax.swing.JTextArea bakerNotes;
    private javax.swing.ButtonGroup buttonGroup1;
    private javax.swing.JTextField calPerSrv;
    private javax.swing.JTextField cookingTime;
    private javax.swing.JTextField costPerServing;
    private javax.swing.JButton delIngd;
    private javax.swing.JTextField flourWeight;
    private javax.swing.JRadioButtonMenuItem gUnit;
    private javax.swing.JTextField hydLevel;
    private javax.swing.JTable ingdTable;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel14;
    private javax.swing.JLabel jLabel15;
    private javax.swing.JLabel jLabel16;
    private javax.swing.JLabel jLabel18;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JMenu jMenu1;
    private javax.swing.JMenu jMenu2;
    private javax.swing.JMenu jMenu3;
    private javax.swing.JMenuItem jMenuItem1;
    private javax.swing.JMenuItem jMenuItem2;
    private javax.swing.JMenuItem jOpenRec;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JPanel jPanel4;
    private javax.swing.JPanel jPanel5;
    private javax.swing.JPanel jPanel6;
    private javax.swing.JPanel jPanel7;
    private javax.swing.JPanel jPanel8;
    private javax.swing.JPanel jPanel9;
    private javax.swing.JMenuItem jSaveRec;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane3;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JRadioButtonMenuItem kgUnit;
    private javax.swing.JRadioButtonMenuItem lbUnit;
    private javax.swing.JMenuItem loadIngdMenu;
    private javax.swing.JRadioButtonMenuItem mPercentage;
    private javax.swing.JRadioButtonMenuItem mQuantity;
    private javax.swing.JPanel mainPanel;
    private javax.swing.JMenuBar menuBar;
    private javax.swing.JButton newIngd;
    private javax.swing.JRadioButtonMenuItem ozUnit;
    private javax.swing.JTextField preparationTime;
    private javax.swing.JProgressBar progressBar;
    private javax.swing.JTextField readyIn;
    private javax.swing.JTextPane recipeText;
    private javax.swing.JLabel recipeTitle;
    private javax.swing.JTextField resizeFactor;
    private javax.swing.JMenuItem saveAs;
    private javax.swing.JTextField servingWeight;
    private javax.swing.JSpinner servings;
    private javax.swing.JEditorPane simpleIngd;
    private javax.swing.JTextField source;
    private javax.swing.JLabel statusAnimationLabel;
    private javax.swing.JLabel statusMessageLabel;
    private javax.swing.JPanel statusPanel;
    private javax.swing.JTextField totalCalories;
    private javax.swing.JTextField totalCost;
    private javax.swing.JTextField totalWeight;
    private javax.swing.ButtonGroup unitGroup;
    private javax.swing.JTextField yield;
    // End of variables declaration//GEN-END:variables
    private final Timer messageTimer;
    private final Timer busyIconTimer;
    private final Icon idleIcon;
    private final Icon[] busyIcons = new Icon[15];
    private int busyIconIndex = 0;
    private JDialog aboutBox;
    private Recipe recipe;
    private ArrayList<Ingredient> ingredients;
    DecimalFormat df = new DecimalFormat("#.##");
    private double oldResizeFactor = 1;
    
    //Create a file chooser
    final JFileChooser fc = new JFileChooser();
    File ingdFile = null;
    String openedFile = null;
    
    private void recipeChanged() {
//        if(recipe != null) {
//            recipe.removePropertyChangeListener(this);
//        }
        
        updateRecipeTitle(recipe.getName());

        ingdTable.setModel(new IngredientTableModel(recipe, ingredients));
        totalWeight.setText(df.format(recipe.getTotalWeight()/ recipe.getToGramFactor()));
        totalCalories.setText(df.format(recipe.getTotalCalories()));
        flourWeight.setText(df.format(recipe.getFlourWeight() / recipe.getToGramFactor()));
        hydLevel.setText(df.format(recipe.getHydrationLevel()));
        servings.setValue(recipe.getServings());
        calPerSrv.setText(df.format(recipe.getCaloriesPerServing()));
        servingWeight.setText(df.format(recipe.getWeightPerServing() / recipe.getToGramFactor()));
        totalCost.setText(df.format(recipe.getCost()));
        costPerServing.setText(df.format(recipe.getCostPerServing()));
        bakerNotes.setText(recipe.getBakerNotes());
        if(recipe.getMeasurementType().equals(MeasurementType.QUANTITY)) {
            mQuantity.setSelected(true);
        } else if(recipe.getMeasurementType().equals(MeasurementType.PERCENTAGE)) {
            mPercentage.setSelected(true);
        }
        
        if(recipe.getUnit().equals(Unit.g)) gUnit.setSelected(true);
        if(recipe.getUnit().equals(Unit.kg)) kgUnit.setSelected(true);
        if(recipe.getUnit().equals(Unit.oz)) ozUnit.setSelected(true);
        if(recipe.getUnit().equals(Unit.lb)) lbUnit.setSelected(true);
        
        preparationTime.setText(recipe.getPreTime());
        cookingTime.setText(recipe.getCookingTime());
        readyIn.setText(recipe.getReadyIn());
        yield.setText(recipe.getYield());
        resizeFactor.setText(recipe.getResizeFactor() + "");
        source.setText(recipe.getSource());
        actFlourWeight.setText(df.format((recipe.getActualFlourWeight()/ recipe.getToGramFactor())));
        recipeText.setText(recipe.getRecipe());
                
        recipe.addPropertyChangeListener(this);
                
        TableColumn column = null;
        for (int i = 0; i < IngredientTableModel.COLUMN.length; i++) {
            column = ingdTable.getColumnModel().getColumn(i);
            if (i == 0) {
                column.setPreferredWidth(5);
            } else if(i == 5) {
                column.setPreferredWidth(200);
            } else {
                column.setPreferredWidth(10);
            }
        }
        
        ingdTable.getColumnModel().getColumn(5).setCellEditor(new DefaultCellEditor(ingdList));
        ingdTable.getColumnModel().getColumn(2).setCellEditor(new DefaultCellEditor(ingdUnit));
        
        updateHTMLDetails();
    }

    private void loadIngredients() {
            ingredients = new ArrayList<Ingredient>();
            File file = new File("Ingredients.ingd");
            System.out.println(file.getAbsoluteFile());
            if(!file.exists()) {
                int returnVal = fc.showOpenDialog(null);
                if (returnVal != JFileChooser.APPROVE_OPTION) {
                    System.exit(-1);
                }
                file = fc.getSelectedFile();
            }
            
            loadIngredients(file);           
    }

    private void loadUnits() {
        ingdUnit = new JComboBox(Unit.values());
    }

    public void propertyChange(PropertyChangeEvent evt) {
        System.out.println("View Properties Rec: " + evt.getPropertyName());
        if(evt.getPropertyName().equals(Recipe.PROP_TOTALWEIGHT)) {
            totalWeight.setText(df.format((Double) evt.getNewValue()/ recipe.getToGramFactor()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_TOTALCALORIES)) {
            totalCalories.setText(df.format(evt.getNewValue()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_FLOURWEIGHT)) {
            flourWeight.setText(df.format((Double) evt.getNewValue()/ recipe.getToGramFactor()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_HYDRATIONLEVEL)) {
            hydLevel.setText(df.format(evt.getNewValue()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_CALORIESPERSERVING)) {
            calPerSrv.setText(df.format(evt.getNewValue()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_WEIGHTPERSERVING)) {
            servingWeight.setText(df.format((Double) evt.getNewValue() / recipe.getToGramFactor()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_COST)) {
            System.out.println("Cost chagned:\t" + evt.getOldValue() + " --> " + evt.getNewValue());
            totalCost.setText(df.format((Double) evt.getNewValue()));
        } else if(evt.getPropertyName().equals(Recipe.PROP_COSTPERSERVING)) {
            System.out.println("Cost/Servings chagned:\t" + evt.getOldValue() + " --> " + evt.getNewValue());
            costPerServing.setText(df.format((Double) evt.getNewValue()));
        } 
    }

    private void updateRecipeTitle(String name) {
        recipeTitle.setText("<html><hr><font size='16' color='Red'>" + name
                + "</color><hr/><html>");
    }

    private void unitChanged(Unit unit) {
        if(recipe != null) {
            recipe.setUnit(unit);
            ingdTable.getColumnModel().getColumn(3).setHeaderValue(
                "Weight(" + recipe.getUnit()  + ")");
            ingdTable.getColumnModel().getColumn(5).setHeaderValue(
                recipe.getUnit() + "/Unit");
        }
        ((IngredientTableModel) ingdTable.getModel()).updateAll();
        
        totalWeight.setText(df.format(recipe.getTotalWeight()/ recipe.getToGramFactor()));
        flourWeight.setText(df.format(recipe.getFlourWeight() / recipe.getToGramFactor()));
        actFlourWeight.setText(df.format((recipe.getActualFlourWeight()/ recipe.getToGramFactor())));
        servingWeight.setText(df.format(recipe.getWeightPerServing() / recipe.getToGramFactor()));
        totalCost.setText(df.format(recipe.getCost()/ recipe.getToGramFactor()));
        costPerServing.setText(df.format(recipe.getCost()/ recipe.getToGramFactor() / recipe.getServings()));
    }

    private void updateRecipe() {
        //recipe.setName(recipeTitle.getName());
        recipe.setPreTime(preparationTime.getText());
        recipe.setCookingTime(cookingTime.getText());
        recipe.setReadyIn(readyIn.getText());
        recipe.setSource(source.getText());
        recipe.setServings((Integer) servings.getValue());
        recipe.setYield(yield.getText());
        recipe.setResizeFactor(Double.parseDouble(resizeFactor.getText()));
        recipe.setActualFlourWeight(Double.parseDouble(actFlourWeight.getText()), true);
        recipe.setBakerNotes(bakerNotes.getText());
        recipe.setRecipe(recipeText.getText());
        
        for(int i = 0; i < recipe.getIngredients().size(); i++) {
            System.out.println("UpdateRecipe:" + 
                    recipe.getIngredients().get(i).getIngredient().getId() + "!" +
                    recipe.getIngredients().get(i).getQuantity() + "!" + 
                    recipe.getIngredients().get(i).getUnit().toString());
        }
        
    }

    private void saveCurrentRecipe() {
        //Save recipe
        updateRecipe();
        System.out.println("Recipe in View:" + recipe);
        Properties rprop = new Properties();
        rprop.put("name",               recipe.getName());
        rprop.put("Preparation_Time",   recipe.getPreTime());
        rprop.put("Cooking_Time", recipe.getCookingTime());
        rprop.put("Ready_In", recipe.getReadyIn());
        rprop.put("Source", recipe.getSource());
        rprop.put("Servings", recipe.getServings() + "");
        rprop.put("Yield", recipe.getYield());
        rprop.put("Resize_Factor", recipe.getResizeFactor() + "");
        rprop.put("Actual_Flour_Weight", recipe.getActualFlourWeight() + "");
        rprop.put("Baker_Notes", recipe.getBakerNotes());
        rprop.put("Recipe", recipe.getRecipe());
        rprop.put("Unit", recipe.getUnit().toString()) ;
        rprop.put("Measurement_Type", recipe.getMeasurementType().toString());
        
        rprop.put("Ingredients_Size", recipe.getIngredients().size() + "") ;
        for(int i = 0; i < recipe.getIngredients().size(); i++) {
            rprop.put("Ingredients_" + i, 
                    recipe.getIngredients().get(i).getIngredient().getId() + "!" +
                    recipe.getIngredients().get(i).getQuantity() + "!" + 
                    recipe.getIngredients().get(i).getUnit().toString() + "!" + 
                    recipe.getIngredients().get(i).getDetails());
        }
        
        //Saving the file
        if (openedFile == null) {
            int returnVal = fc.showSaveDialog(null);
            if (returnVal == JFileChooser.APPROVE_OPTION) {
                openedFile = fc.getSelectedFile().getAbsolutePath();
            } else {
                return;
            }
        }
 
        try {
            rprop.store(new FileOutputStream(openedFile), null);
        } catch (IOException ex) {
            Logger.getLogger(SimpleRecipesView.class.getName()).log(Level.SEVERE, null, ex);
        }
       
        getFrame().setTitle(recipe.getName() + " - " + openedFile);
    }

    private void loadIngredients(File file) {
        BufferedReader in = null;
        try {
            ingredients.clear();
            System.out.println("Loading ingredients from ..." + file.getAbsolutePath());
            int lCount = 0;
            in = new BufferedReader(new InputStreamReader(new FileInputStream(
                    file.getAbsoluteFile()), "UTF-8"));
                    //new FileReader(file.getAbsoluteFile()));
            String line = null;
            String[] sgmt = null;
            while ((line = in.readLine()) != null) {
                if (!line.trim().startsWith("#") && line.trim().length() > 0) {
                    lCount++;
                    sgmt = line.split("\t");
                    System.out.println(lCount + "\t" + line);
                    ingredients.add(new Ingredient(
                            Integer.parseInt(sgmt[0]),
                            sgmt[6], sgmt[2],
                            Double.parseDouble(sgmt[3]),
                            Double.parseDouble(sgmt[5]),
                            sgmt[1].equals("F") ? IngredientType.FLOUR
                            : sgmt[1].equals("H") ? IngredientType.HYDRATION
                            : IngredientType.OTHER,
                            Double.parseDouble(sgmt[4])));
                }
            }
            in.close();
            
            ingdList = new SortedComboList();
            ingdList.addMouseListener(new MouseAdapter(){
                public void mousePressed(MouseEvent evt) {
                  if (evt.isPopupTrigger()) {
                      System.out.println(
                      ingdList.getSelectedItem());
                  }
                }
            });
            for (int i = 0; i < ingredients.size(); i++) {
                ingdList.addItem(ingredients.get(i));
            }
        } catch (IOException ex) {
            Logger.getLogger(SimpleRecipesView.class.getName()).log(Level.SEVERE, null, ex);
        } finally {
            try {
                in.close();
            } catch (IOException ex) {
                Logger.getLogger(SimpleRecipesView.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    private void updateHTMLDetails() {
        StringBuilder buff = new StringBuilder();
        MesuredIngredient ingd = null;
        String item = null;
        if (recipe != null) {
            buff.append("<style>\n");
            buff.append("h1 {font-size:30px;}\n");
            buff.append("h2 {font-size:25px;}\n");
            buff.append("h3 {font-size:20px;}\n");
            buff.append("p {font-size:14px;}\n");
            buff.append("</style>\n");
            buff.append("<h1>Ingredients</h1>");
            buff.append("<table width='60%'>");
            for (int i = 0; i < recipe.getIngredients().size(); i++) {
                ingd = recipe.getIngredients().get(i);
                buff.append("<tr>");
                buff.append("<td>").append(MesuredIngredientAdaptor.toFraction(
                        ingd.getQuantity())).append("</td>");
                buff.append("<td>").append(ingd.getUnit()).append("</td>");
                buff.append("<td>").append(df.format(ingd.getWeight())).append("g").append("</td>");
                buff.append("<td>").append(ingd.getIngredient().getName()).
                        append(ingd.getDetails().length() > 0?"; ":"").append(
                        ingd.getDetails()).append("</td>");
                buff.append("</tr>");
            }
            buff.append("</table>");


            //process the recipe;
            boolean inBullets = false;
            String[] lines = recipeText.getText().split("\n");
            for (int i = 0; i < lines.length; i++) {
                if (lines[i].trim().startsWith("=") && lines[i].trim().endsWith("=")) {
                    int hCount = 0;
                    int j = 0;
                    while (j < lines[i].trim().length()) {
                        if (lines[i].trim().charAt(j) == '=') {
                            hCount++;
                        } else {
                            break;
                        }
                        j++;
                    }
                    buff.append("<h" + hCount + ">"
                            + lines[i].trim().replace("=", "")
                            + "</h" + hCount + ">");
                } else {
                    buff.append(fixRecipeLine(lines[i]));
                }
            }

            simpleIngd.setText(buff.toString());
            System.out.println(buff.toString());
        }
    }

    
    class SortedComboList extends JComboBox {
         public void addItem(Object anObject) {
            int size = ((DefaultComboBoxModel) dataModel).getSize();
            Object obj;
            boolean added = false;
            for (int i = 0; i < size; i++) {
                obj = dataModel.getElementAt(i);
                int compare = anObject.toString().compareToIgnoreCase(obj.toString());
                if (compare <= 0) { // if anObject less than or equal obj
                    super.insertItemAt(anObject, i);
                    added = true;
                    break;
                }
            }

            if (!added) {
                super.addItem(anObject);
            }
        }
    }
    
    private Ingredient findIngredientByID(int id) {
        for(int i = 0; i < ingredients.size(); i++) {
            if(id == ingredients.get(i).getId())
                return ingredients.get(i);
        }
        return null;
    }
}
